#pragma once

#include <PosGraph/Math/VectorT.h>
#include <PosGraph/Modeling/Object.h>
#include <PosGraph/Rendering/Color.h>
#include <PosGraph/GL/gl.h>

#include <PosGraph/Rendering/ViewingParameters.h>
#include <ctime>
#include <vector>
#include <string>
using namespace std;


// COpenGLView view

class COpenGLView : public CView
{
	DECLARE_DYNCREATE(COpenGLView)

protected:
	COpenGLView();           // protected constructor used by dynamic creation
	virtual ~COpenGLView();

public:
	virtual void OnDraw(CDC* pDC);      // overridden to draw this view
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	DECLARE_MESSAGE_MAP()


protected:
	virtual bool SetupPixelFormat(void);

	virtual void PreRenderScene(void);
	virtual void RenderStockScene(void);
  virtual void RenderScene();
  virtual void GLDraw();
	

protected:
	HGLRC m_hRC;
	CDC*  m_pDC;
	static const char* const _ErrorStrings[];
	const char* m_ErrorString;

	void SetError(int e);
	virtual bool InitializeOpenGL();

protected:	
	int			m_nViewWidth, m_nViewHeight;

	CPoint  m_ptFrom;
	CPoint	m_ptTo;

	bool		m_bLMBPressed;
	bool		m_bMMBPressed;
	bool		m_bAltPressed;
	bool		m_bCtrlPressed;

protected:
	bool		m_bShowStockScene;


protected:
	float		m_fFPS;

public:
	float		GetFPS() const		{ return m_fFPS; }
	int			nAuxBuffers;

	// message maps
protected:
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnDestroy(void);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
  afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);


protected:
  PosGraph::Math::Vec3f   m_vCenter;
	float		                m_fRadius;  

  CPoint                  m_ptPickWindow[2];
  CPoint                  m_ptLastPoint2D;
  PosGraph::Math::Vec3f   m_vLastPoint3D;
  bool                    m_bLastPointOK;

  ViewingParameters       m_ViewingParameters;

/// picking
protected:  

  struct SelectedPrimitiveInfo
  {
    PosGraph::Modeling::Object*         _pObject;
    PosGraph::Modeling::PrimitiveType   _ePrimitiveType;
    int                                 _nIdx;
  };

  virtual void GLPick();
	virtual void GLProcessHits(bool bMultiSelect, GLint nNumHits, GLuint uiBuffer[]);
  virtual void GLReadSelectedPrimitiveInfo(GLuint **pos, float z[2], SelectedPrimitiveInfo &info);
  virtual void debugPrintSelectedPrimitiveInfo(const SelectedPrimitiveInfo &info);
  // override the followings for picking
  virtual void GLSelectModeDraw()                                       {}
  virtual void selectMeshPrimitive(const SelectedPrimitiveInfo &info)   {}
  virtual void clearSelectedMeshPrimitives()                            {}


protected:
  // translate the scene and update modelview matrix
  void translate(const PosGraph::Math::Vec3f &vTrans);

  // rotate the scene (around its center) and update modelview matrix
  void rotate(const PosGraph::Math::Vec3f &vAxis, float fAngle);

	// virtual trackball: map 2D screen point to unit sphere
	bool mapToSphere(const CPoint &pt2D, PosGraph::Math::Vec3f &v3D);

  const GLdouble* modelviewMatrix() const   { return  m_ViewingParameters.modelviewMatrix(); }
  const GLdouble* projectionMatrix() const  { return  m_ViewingParameters.projectionMatrix(); }
  float fovy() const                        { return  m_ViewingParameters.getFovy(); }


  // updates projection matrix
	virtual void updateProjectionMatrix();


  void makeCurrent();

public:
  /** Sets the center and size of the whole scene. 
	The _center is used as fixpoint for rotations and for adjusting
	the camera/viewer (see view_all()). */
  void setScenePos(const PosGraph::Math::Vec3f& vCenter, float fRadius);

  virtual void viewAll();

  int width() const       { return  m_nViewWidth; }
  int height() const      { return  m_nViewHeight; }

  const ViewingParameters& getViewingParameters() const     { return  m_ViewingParameters; }
  ViewingParameters& getViewingParameters()                 { return  m_ViewingParameters; }

  void  captureFrameBuffer(const std::string &strFilename);
  //void  capturePDF(const std::string &strFilename);
};

